package csel.view;

import javax.swing.*;

import java.awt.*;
import csel.model.*;
import csel.model.entity.NonPlayerCharacter;
import csel.model.entity.PlayerCharacter;
import csel.model.items.*;
import csel.model.skills.Skill;
import csel.view.dialog.NPCDialogueDialog;
import csel.controller.bindings.Bindable;
import csel.view.dialog.*;

public class GameViewport extends Viewport implements Invoker, Observer<Object>
{
	private final JFrame myFrame;
	private final AreaViewport areaView;
	private final StatusViewport statusView;
	private final JPanel basePanel;
	private final JLayeredPane layerPane;
	private final TrampolineListener trampy;
	private TradeDialog myDialog;
	private PlayerCharacter myCharacter;
	private Model myModel;
	
	public GameViewport(Model m)
	{
		trampy = new TrampolineListener();
		myModel = m;
		myCharacter = m.getPlayerCharacter();
		myCharacter.addObserver(this);
		m.addObserver(this);
		
		areaView = new AreaViewport(m, trampy);
		statusView = new StatusViewport(m, trampy);
		
		myFrame = new JFrame("CISE Labyrinth - Iteration #2 - Team Awesome");
		myFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
		myFrame.addKeyListener(trampy);
		myFrame.setLayout(null);
		myFrame.setResizable(false);

		basePanel = new JPanel();
		basePanel.add(statusView.getIDPanel(),BorderLayout.WEST);
		basePanel.add(statusView.getBottomMenu(),BorderLayout.EAST);

		//Take care of layering
		layerPane = myFrame.getLayeredPane();
		//layerpane.setBackground(Color.BLACK);
		JPanel myBackground = new JPanel();
		myBackground.setBackground(Color.black);
		layerPane.add(myBackground,JLayeredPane.DEFAULT_LAYER);
		layerPane.add(areaView.getContainer(), JLayeredPane.PALETTE_LAYER);
		layerPane.add(statusView.getNumBar(), JLayeredPane.PALETTE_LAYER);
		layerPane.add(basePanel, JLayeredPane.PALETTE_LAYER);

		myBackground.setBounds(0,0,650,850);
		
		basePanel.setOpaque(false);
		areaView.getContainer().setBounds(25, 50, 600, 600);
		statusView.getNumBar().setBounds(25, 0, 650, 50);
		basePanel.setBounds(40, 650, 600, 130);

		myFrame.setSize(650, 850);
		myFrame.setBackground(Color.BLACK);
		layerPane.setVisible(true);
		areaView.setVisible(true);
		myFrame.setVisible(true);
		areaView.startRendering();
	}
	
	public int getOffset()
	{
		return statusView.getOffset();
	}
	
	public void accept(GameCommand gc)
	{
		gc.execute();
	}
	
	protected Container getContainer()
	{
		return myFrame;
	}
	
	public void setVisible(boolean b)
	{
		myFrame.setVisible(b);
	}
	
	public void close()
	{
		areaView.close();
		statusView.close();
		SwingUtilities.invokeLater(new Runnable()
		{
			public void run()
			{
				myFrame.dispose();
			}
		});
		System.out.println("[VIEW] GameViewport closed");
	}
	
	public void toggleMenu()
	{
		statusView.toggleMenu();
	}
	
	public void rotateBar()
	{
		statusView.rotateBar();
	}
	
	public void nextBarMode()
	{
		statusView.nextMode();
	}
	
	// Accessors for Inventory/Equipment/Skill Selected Items
	
	public TakeableItem getSelectedInventoryItem()
	{
		return statusView.getSelectedInventoryItem();
	}
	
	public EquippableItem getSelectedEquipmentItem()
	{
		return statusView.getSelectedEquipmentItem();
	}
	
	public Skill getSelectedSkill()
	{
		return statusView.getSelectedSkill();
	}
	
	// Setting the NumberBar modes
	
	public void setSkillMode()
	{
		statusView.setMode(0);
	}
	
	public void setInventoryMode()
	{
		statusView.setMode(1);
	}
	
	public void setEquipmentMode()
	{
		statusView.setMode(2);
	}
	
	// Opening one of the menus
	// this logic is encapsulated within the view so these ints should be okay!
	// stats == 0, skills == 1, inv == 2, equip == 3, system == 4
	public void setSkillMenu()
	{
		statusView.setMenu(1);
	}
	
	public void setStatsMenu()
	{
		statusView.setMenu(0);
	}
	
	public void setSystemMenu()
	{
		statusView.setMenu(4);
	}
	
	public void setInventoryMenu()
	{
		statusView.setMenu(2);
	}
	
	public void setEquipmentMenu()
	{
		statusView.setMenu(3);
	}
	
	//DIALOG METHODS
	public void showControlDialog(Bindable b)
	{
		Component[] popupLayerComponents = layerPane.getComponentsInLayer(JLayeredPane.POPUP_LAYER);
		int size = popupLayerComponents.length;
		if (size == 0)
		{
			ChangeControlsDialog myDialog = new ChangeControlsDialog(b, trampy);
		}
		//layerPane.add(myDialog,JLayeredPane.POPUP_LAYER);
		//myDialog.setBounds(200,200,400,400);
	}
	
	public void showNPCDialog(NonPlayerCharacter npc)
	{
		Component[] popupLayerComponents = layerPane.getComponentsInLayer(JLayeredPane.POPUP_LAYER);
		int size = popupLayerComponents.length;
		if (size == 0)
		{
			NPCDialogueDialog myDialog = new NPCDialogueDialog(npc, trampy);
			layerPane.add(myDialog,JLayeredPane.POPUP_LAYER);
			myDialog.setBounds(50,50,275,80);
		}
	}
	
	public void showTradeDialog()
	{
		hideDialog();
		
		Component[] popupLayerComponents = layerPane.getComponentsInLayer(JLayeredPane.POPUP_LAYER);
		int size = popupLayerComponents.length;
		if ((size == 0)&&(myCharacter.getInteractingCharacter() != null))
		{
			myDialog = TradeDialog.initialize(myCharacter,myCharacter.getInteractingCharacter(), trampy);
			layerPane.add(myDialog,JLayeredPane.POPUP_LAYER);
			myDialog.setBounds(50,50,400,600);
		}
	}
	
	public TakeableItem getBuyItem()
	{
		return myDialog.getBuyItem();
	}
	
	public TakeableItem getSellItem()
	{
		return myDialog.getSellItem();
	}
	
	public void showSaveDialog()
	{
		ViewUtils.promptSaveDialog(this);
	}
	
	public void showLoadDialog()
	{
		ViewUtils.promptOpenDialog(this);
	}
	
	public void showNewDialog()
	{
		
	}
	
	public void hideDialog()
	{
		Component[] popupLayerComponents = layerPane.getComponentsInLayer(JLayeredPane.POPUP_LAYER);
		int size = popupLayerComponents.length;
		for (Component c: popupLayerComponents)
		{
			layerPane.remove(c);
		}
	}
	
	public void mupdate(Object o, Object param)
	{
		if (o == myCharacter)
		{
			if (myCharacter.getInteractingCharacter() != null)
			{
				showNPCDialog(((NonPlayerCharacter) myCharacter.getInteractingCharacter()));
			}
		}
		else if (o == myModel)
		{
			myCharacter.removeObserver(this);
			myCharacter = myModel.getPlayerCharacter();
			myCharacter.addObserver(this);
		}
	}
	
}
